<!DOCTYPE html>


<html theme="dark" showBanner="true" hasBanner="false" > 
<link href="/blog/fontawesome/css/fontawesome.css" rel="stylesheet">
<link href="/blog/fontawesome/css/brands.css" rel="stylesheet">
<link href="/blog/fontawesome/css/solid.css" rel="stylesheet">
<script src="/blog/js/color.global.min.js" ></script>
<script src="/blog/js/load-settings.js" ></script>
<head>
  <meta charset="utf-8">
  
  
  

  
  <title>Hexo</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  <link rel="preload" href="/blog/css/fonts/Roboto-Regular.ttf" as="font" type="font/ttf" crossorigin="anonymous">
  <link rel="preload" href="/blog/css/fonts/Roboto-Bold.ttf" as="font" type="font/ttf" crossorigin="anonymous">

  <meta name="description" content="如果我们需要编写一个DRM驱动，我们应该怎么做呢？具体流程如下： (1) 定义struct drm_driver，并初始化成员name、desc、data、major、minor、driver_features、fops、dumb_create等； (2)调用drm_dev_alloc函数分配并初始化一个struct drm_device； (3) 调用drm_mode_config_init初始">
<meta property="og:type" content="article">
<meta property="og:title" content="Hexo">
<meta property="og:url" content="https://zyly2033.gitee.io/2023/09/11/rk3399/Rockchip%20RK3399%20-%20DRM%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:description" content="如果我们需要编写一个DRM驱动，我们应该怎么做呢？具体流程如下： (1) 定义struct drm_driver，并初始化成员name、desc、data、major、minor、driver_features、fops、dumb_create等； (2)调用drm_dev_alloc函数分配并初始化一个struct drm_device； (3) 调用drm_mode_config_init初始">
<meta property="og:locale" content="en_US">
<meta property="og:image" content="https://gitee.com/zyly2033/blog-pic/raw/master/202309102233517.png">
<meta property="og:image" content="https://gitee.com/zyly2033/blog-pic/raw/master/202309102246770.png">
<meta property="article:published_time" content="2023-09-11T12:23:16.294Z">
<meta property="article:modified_time" content="2023-09-10T15:33:19.284Z">
<meta property="article:author" content="John Doe">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://gitee.com/zyly2033/blog-pic/raw/master/202309102233517.png">
  
    <link rel="alternate" href="/blog/atom.xml" title="Hexo" type="application/atom+xml">
  
  
    <link rel="icon" media="(prefers-color-scheme: light)" href="/blog/images/favicon-light-32.png" sizes="32x32">
    <link rel="icon" media="(prefers-color-scheme: light)" href="/blog/images/favicon-light-128.png" sizes="128x128">
    <link rel="icon" media="(prefers-color-scheme: light)" href="/blog/images/favicon-light-180.png" sizes="180x180">
    <link rel="icon" media="(prefers-color-scheme: light)" href="/blog/images/favicon-light-192.png" sizes="192x192">
    <link rel="icon" media="(prefers-color-scheme: dark)" href="/blog/images/favicon-dark-32.png" sizes="32x32">
    <link rel="icon" media="(prefers-color-scheme: dark)" href="/blog/images/favicon-dark-128.png" sizes="128x128">
    <link rel="icon" media="(prefers-color-scheme: dark)" href="/blog/images/favicon-dark-180.png" sizes="180x180">
    <link rel="icon" media="(prefers-color-scheme: dark)" href="/blog/images/favicon-dark-192.png" sizes="192x192">
  
  
<link rel="stylesheet" href="/blog/css/style.css">

<meta name="generator" content="Hexo 6.3.0"></head>

<body>
  
   
  <div id="main-grid" class="shadow   ">
    <div id="nav" class=""  >
      <navbar id="navbar">
  <nav id="title-nav">
    <a href="/blog/">
      <div id="vivia-logo">
        <div class="dot"></div>
        <div class="dot"></div>
        <div class="dot"></div>
        <div class="dot"></div>
      </div>
      <div>Hexo </div>
    </a>
  </nav>
  <nav id="main-nav">
    
      <a class="main-nav-link" href="/blog/">Home</a>
    
      <a class="main-nav-link" href="/blog/archives">Archives</a>
    
      <a class="main-nav-link" href="/blog/about">About</a>
    
  </nav>
  <nav id="sub-nav">
    <a id="theme-btn" class="nav-icon">
      <span class="light-mode-icon"><svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M438.5-829.913v-48q0-17.452 11.963-29.476 11.964-12.024 29.326-12.024 17.363 0 29.537 12.024t12.174 29.476v48q0 17.452-11.963 29.476-11.964 12.024-29.326 12.024-17.363 0-29.537-12.024T438.5-829.913Zm0 747.826v-48q0-17.452 11.963-29.476 11.964-12.024 29.326-12.024 17.363 0 29.537 12.024t12.174 29.476v48q0 17.452-11.963 29.476-11.964 12.024-29.326 12.024-17.363 0-29.537-12.024T438.5-82.087ZM877.913-438.5h-48q-17.452 0-29.476-11.963-12.024-11.964-12.024-29.326 0-17.363 12.024-29.537t29.476-12.174h48q17.452 0 29.476 11.963 12.024 11.964 12.024 29.326 0 17.363-12.024 29.537T877.913-438.5Zm-747.826 0h-48q-17.452 0-29.476-11.963-12.024-11.964-12.024-29.326 0-17.363 12.024-29.537T82.087-521.5h48q17.452 0 29.476 11.963 12.024 11.964 12.024 29.326 0 17.363-12.024 29.537T130.087-438.5Zm660.174-290.87-34.239 32q-12.913 12.674-29.565 12.174-16.653-.5-29.327-13.174-12.674-12.673-12.554-28.826.12-16.152 12.794-28.826l33-35q12.913-12.674 30.454-12.674t30.163 12.847q12.709 12.846 12.328 30.826-.38 17.98-13.054 30.653ZM262.63-203.978l-32 34q-12.913 12.674-30.454 12.674t-30.163-12.847q-12.709-12.846-12.328-30.826.38-17.98 13.054-30.653l33.239-31q12.913-12.674 29.565-12.174 16.653.5 29.327 13.174 12.674 12.673 12.554 28.826-.12 16.152-12.794 28.826Zm466.74 33.239-32-33.239q-12.674-12.913-12.174-29.565.5-16.653 13.174-29.327 12.673-12.674 28.826-13.054 16.152-.38 28.826 12.294l35 33q12.674 12.913 12.674 30.454t-12.847 30.163q-12.846 12.709-30.826 12.328-17.98-.38-30.653-13.054ZM203.978-697.37l-34-33q-12.674-12.913-13.174-29.945-.5-17.033 12.174-29.707t31.326-13.293q18.653-.62 31.326 13.054l32 34.239q11.674 12.913 11.174 29.565-.5 16.653-13.174 29.327-12.673 12.674-28.826 12.554-16.152-.12-28.826-12.794ZM480-240q-100 0-170-70t-70-170q0-100 70-170t170-70q100 0 170 70t70 170q0 100-70 170t-170 70Zm-.247-82q65.703 0 111.475-46.272Q637-414.544 637-480.247t-45.525-111.228Q545.95-637 480.247-637t-111.475 45.525Q323-545.95 323-480.247t45.525 111.975Q414.05-322 479.753-322ZM481-481Z"/></svg></span>
      <span class="dark-mode-icon"><svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M480.239-116.413q-152.63 0-258.228-105.478Q116.413-327.37 116.413-480q0-130.935 77.739-227.435t206.304-125.043q43.022-9.631 63.87 10.869t3.478 62.805q-8.891 22.043-14.315 44.463-5.424 22.42-5.424 46.689 0 91.694 64.326 155.879 64.325 64.186 156.218 64.186 24.369 0 46.978-4.946 22.609-4.945 44.413-14.076 42.826-17.369 62.967 1.142 20.142 18.511 10.511 61.054Q807.174-280 712.63-198.206q-94.543 81.793-232.391 81.793Zm0-95q79.783 0 143.337-40.217 63.554-40.218 95.793-108.283-15.608 4.044-31.097 5.326-15.49 1.283-31.859.805-123.706-4.066-210.777-90.539-87.071-86.473-91.614-212.092-.24-16.369.923-31.978 1.164-15.609 5.446-30.978-67.826 32.478-108.282 96.152Q211.652-559.543 211.652-480q0 111.929 78.329 190.258 78.329 78.329 190.258 78.329ZM466.13-465.891Z"/></svg></span>
    </a>
    
      <a id="nav-rss-link" class="nav-icon mobile-hide" href="/blog/atom.xml" title="RSS Feed">
        <svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M198-120q-25.846 0-44.23-18.384-18.384-18.385-18.384-44.23 0-25.846 18.384-44.23 18.384-18.385 44.23-18.385 25.846 0 44.23 18.385 18.384 18.384 18.384 44.23 0 25.845-18.384 44.23Q223.846-120 198-120Zm538.385 0q-18.846 0-32.923-13.769-14.076-13.769-15.922-33.23-8.692-100.616-51.077-188.654-42.385-88.039-109.885-155.539-67.5-67.501-155.539-109.885Q283-663.462 182.385-672.154q-19.461-1.846-33.23-16.23-13.769-14.385-13.769-33.846t14.076-32.922q14.077-13.461 32.923-12.23 120.076 8.692 226.038 58.768 105.961 50.077 185.73 129.846 79.769 79.769 129.846 185.731 50.077 105.961 58.769 226.038 1.231 18.846-12.538 32.922Q756.461-120 736.385-120Zm-252 0q-18.231 0-32.423-13.461t-18.653-33.538Q418.155-264.23 348.886-333.5q-69.27-69.27-166.501-84.423-20.077-4.462-33.538-18.961-13.461-14.5-13.461-33.346 0-19.076 13.884-33.23 13.884-14.153 33.115-10.922 136.769 15.384 234.384 112.999 97.615 97.615 112.999 234.384 3.231 19.23-10.538 33.115Q505.461-120 484.385-120Z"/></svg>
      </a>
    
    <div id="nav-menu-btn" class="nav-icon">
      <svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M177.37-252.282q-17.453 0-29.477-11.964-12.024-11.963-12.024-29.326t12.024-29.537q12.024-12.174 29.477-12.174h605.26q17.453 0 29.477 11.964 12.024 11.963 12.024 29.326t-12.024 29.537q-12.024 12.174-29.477 12.174H177.37Zm0-186.218q-17.453 0-29.477-11.963-12.024-11.964-12.024-29.326 0-17.363 12.024-29.537T177.37-521.5h605.26q17.453 0 29.477 11.963 12.024 11.964 12.024 29.326 0 17.363-12.024 29.537T782.63-438.5H177.37Zm0-186.217q-17.453 0-29.477-11.964-12.024-11.963-12.024-29.326t12.024-29.537q12.024-12.174 29.477-12.174h605.26q17.453 0 29.477 11.964 12.024 11.963 12.024 29.326t-12.024 29.537q-12.024 12.174-29.477 12.174H177.37Z"/></svg>
    </div>
  </nav>
</navbar>
<div id="nav-dropdown" class="hidden">
  <div id="dropdown-link-list">
    
      <a class="nav-dropdown-link" href="/blog/">Home</a>
    
      <a class="nav-dropdown-link" href="/blog/archives">Archives</a>
    
      <a class="nav-dropdown-link" href="/blog/about">About</a>
    
    
      <a class="nav-dropdown-link" href="/blog/atom.xml" title="RSS Feed">RSS</a>
     
    </div>
</div>
<script>
  let dropdownBtn = document.getElementById("nav-menu-btn");
  let dropdownEle = document.getElementById("nav-dropdown");
  dropdownBtn.onclick = function() {
    dropdownEle.classList.toggle("hidden");
  }
</script>
    </div>
    <div id="sidebar-wrapper">
      <sidebar id="sidebar">
  
    <div class="widget-wrap">
  <div class="info-card">
    <div class="avatar">
      
      <div class="img-dim"></div>
    </div>
    <div class="info">
      <div class="username">Your Name </div>
      <div class="dot"></div>
      <div class="subtitle">This is the subtitle </div>
      <div class="link-list">
        
          <a class="link-btn" target="_blank" rel="noopener" href="https://twitter.com" title="Twitter"><i class="fa-brands fa-twitter"></i></a>
        
          <a class="link-btn" target="_blank" rel="noopener" href="https://store.steampowered.com" title="Steam"><i class="fa-brands fa-steam"></i></a>
        
          <a class="link-btn" target="_blank" rel="noopener" href="https://github.com" title="GitHub"><i class="fa-brands fa-github"></i></a>
         
      </div>  
    </div>
  </div>
</div>

  
  <div class="sticky">
    
      



    
      

    
      
  <div class="widget-wrap">
    <div class="widget">
      <h3 class="widget-title">Archives</h3>
      
      
        <a class="archive-link" href="/blog/archives/2023/09 ">
          September 2023 
          <div class="archive-count">8 </div>
        </a>
      
    </div>
  </div>


    
      
  <div class="widget-wrap">
    <div class="widget">
      <h3 class="widget-title">Recent Posts</h3>
      <ul>
        
          <a class="recent-link" href="/blog/2023/09/11/rk3399/Rockchip%20RK3399%20-%20DRM%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F/" title="" >
            <div class="recent-link-text">
              (no title)
            </div>
          </a>
        
          <a class="recent-link" href="/blog/2023/09/11/rk3399/Rockchip%20RK3399%20-%20DRM%E5%AD%90%E7%B3%BB%E7%BB%9F/" title="" >
            <div class="recent-link-text">
              (no title)
            </div>
          </a>
        
          <a class="recent-link" href="/blog/2023/09/11/rk3399/Rockchip%20RK3399%20-%20DRM%20plane/" title="" >
            <div class="recent-link-text">
              (no title)
            </div>
          </a>
        
          <a class="recent-link" href="/blog/2023/09/11/rk3399/Rockchip%20RK3399%20-%20DRM%20framebuffer/" title="" >
            <div class="recent-link-text">
              (no title)
            </div>
          </a>
        
          <a class="recent-link" href="/blog/2023/09/11/rk3399/Rockchip%20RK3399%20-%20DRM%20crtc/" title="" >
            <div class="recent-link-text">
              (no title)
            </div>
          </a>
        
      </ul>
    </div>
  </div>

    
  </div>
</sidebar>
    </div>
    <div id="content-body">
       

<article id="post-rk3399/Rockchip RK3399 - DRM驱动程序" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  
    
   
  <div class="article-inner">
    <div class="article-main">
      <header class="article-header">
        
<div class="main-title-bar">
  <div class="main-title-dot"></div>
  
    
      <h1 class="p-name article-title" itemprop="headline name">
        Untitled
      </h1>
    
  
</div>

        <div class='meta-info-bar'>
          <div class="meta-info">
  <time class="dt-published" datetime="2023-09-11T12:23:16.294Z" itemprop="datePublished">2023-09-11</time>
</div>
          <div class="need-seperator meta-info">
            <div class="meta-cate-flex">
  
    Uncategorized 
   
</div>
  
          </div>
          <div class="wordcount need-seperator meta-info">
            5.5k words 
          </div>
        </div>
        
      </header>
      <div class="e-content article-entry" itemprop="articleBody">
        
          <p>如果我们需要编写一个<code>DRM</code>驱动，我们应该怎么做呢？具体流程如下：</p>
<p>(1) 定义<code>struct drm_driver</code>，并初始化成员<code>name</code>、<code>desc</code>、<code>data</code>、<code>major</code>、<code>minor</code>、<code>driver_features</code>、<code>fops</code>、<code>dumb_create</code>等；</p>
<p>(2)调用<code>drm_dev_alloc</code>函数分配并初始化一个<code>struct drm_device</code>；</p>
<p>(3) 调用<code>drm_mode_config_init</code>初始化<code>drm_device</code>中<code>mode_config</code>结构体；</p>
<p>(4) 调用<code>drm_xxx_init</code>创建 <code>plane</code>、<code>crtc</code>、<code>encoder</code>、<code>connector</code> 这4个 <code>drm_mode_object</code>；</p>
<p>(5) 调用<code>drm_dev_register</code>注册<code>drm_device</code>；</p>
<h3 id="一、设备树配置"><a href="#一、设备树配置" class="headerlink" title="一、设备树配置"></a>一、设备树配置</h3><p>一个显示子系统由<code>LCD</code>控制器（<code>vop</code>）、接口控制器（<code>mipi</code>，<code>lvds</code>，<code>hdmi</code>、<code>edp</code>、<code>dp</code>等)、液晶背光，电源等多个独立的功能模块构成。</p>
<p>因此<code>DRM</code>驱动是由一系列相关功能模块的驱动的结合，它包含了<code>vop</code>、<code>mipi</code>、<code>lvds</code>、<code>hdmi</code>、<code>edp</code>、<code>dp</code>、<code>backlight</code>等等显示通路上的依赖模块。只有这些相互依赖的模块都加载完整，整个<code>drm</code>系统才算启动完成。</p>
<p><img src="https://gitee.com/zyly2033/blog-pic/raw/master/202309102233517.png" alt="img"></p>
<p>因为这些复杂的依赖关系，在<code>drm</code>系统初始化的过程中，可能会出现某个资源暂时未就绪，而导致某个模块暂时无法顺利加载的情况，为了解决这种问题，<code>drm</code> 驱动利用了<code>Linux</code>驱动 中的<code>deferred probe</code>机制，当发现某个依赖的资源未就绪的时候，驱动返回 <code>-EPROBE_DEFER(-517)</code> , 然后退出。<code>Linux kernel</code>会在稍后再次尝试加载这个驱动，直到依赖的资源就绪，驱动顺利加载为止。</p>
<p>在一颗SoC上，可能由多个<code>vop</code>、<code>mipi</code>、<code>lvds</code>、<code>hdmi</code>、<code>edp</code>、<code>dp</code>模块，根据具体产品定义，一款产品可能只需要使用其中一部分模块组成显示通路。具体使用那些模块，以及这些模块之间如何衔接通过<code>dts</code>配置。</p>
<h4 id="1-1-display-subsystem设备节点"><a href="#1-1-display-subsystem设备节点" class="headerlink" title="1.1 display_subsystem设备节点"></a>1.1 <code>display_subsystem</code>设备节点</h4><p>在<code>arch/arm64/boot/dts/rockchip/rk3399.dtsi</code>下定义有<code>display_subsystem</code>设备节点；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"> display_subsystem: display-subsystem &#123;</span><br><span class="line">		compatible = <span class="string">&quot;rockchip,display-subsystem&quot;</span>;</span><br><span class="line">		ports = &lt;&amp;vopl_out&gt;, &lt;&amp;vopb_out&gt;;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>该节点控制<code>rockchip_drm_drv.c</code>驱动的加载。<code>ports</code>属性描述<code>vop</code>硬件资源，<code>vopl_out</code>、<code>vopb_out</code>对应<code>video port l/b</code>两个独立的输出通路。</p>
<h4 id="1-2-vop设备节点"><a href="#1-2-vop设备节点" class="headerlink" title="1.2 vop设备节点"></a>1.2 <code>vop</code>设备节点</h4><p><code>vop</code>节点描述了<code>vop</code>硬件资源，控制<code>vop</code>驱动的加载<code>rockchip_drm_vop.c</code>、 <code>rockchip_drm_vop2.c</code>,它描述了如下的显示通路连接关系：</p>
<p><img src="https://gitee.com/zyly2033/blog-pic/raw/master/202309102246770.png" alt="img"></p>
<p>以设备节点<code>vopl_out</code>为例，<code>port</code>下的<code>endpoint</code>描述的是<code>vop</code>和显示接口的连接关系，<code>vopl_out</code>节点下有<code>vopl_out_mipi</code>，<code>vopl_out_edp</code>，<code>vopl_out_hdmi</code>，<code>vopl_out_mipi1</code>、<code>vopl_out_dp</code>五个节点，说明<code>vopl</code>可以和<code>mipi</code>、<code>edp</code>、<code>hdmi</code>、<code>mipi1</code>、<code>dp</code>五个显示接口连接。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line">vopl: vop@ff8f0000 &#123;</span><br><span class="line">		compatible = &quot;rockchip,rk3399-vop-lit&quot;;</span><br><span class="line">		reg = &lt;0x0 0xff8f0000 0x0 0x2000&gt;, &lt;0x0 0xff8f2000 0x0 0x400&gt;;</span><br><span class="line">		interrupts = &lt;GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH 0&gt;;</span><br><span class="line">		assigned-clocks = &lt;&amp;cru ACLK_VOP1&gt;, &lt;&amp;cru HCLK_VOP1&gt;;</span><br><span class="line">		assigned-clock-rates = &lt;400000000&gt;, &lt;100000000&gt;;</span><br><span class="line">		clocks = &lt;&amp;cru ACLK_VOP1&gt;, &lt;&amp;cru DCLK_VOP1&gt;, &lt;&amp;cru HCLK_VOP1&gt;;</span><br><span class="line">		clock-names = &quot;aclk_vop&quot;, &quot;dclk_vop&quot;, &quot;hclk_vop&quot;;</span><br><span class="line">		iommus = &lt;&amp;vopl_mmu&gt;;</span><br><span class="line">		power-domains = &lt;&amp;power RK3399_PD_VOPL&gt;;</span><br><span class="line">		resets = &lt;&amp;cru SRST_A_VOP1&gt;, &lt;&amp;cru SRST_H_VOP1&gt;, &lt;&amp;cru SRST_D_VOP1&gt;;</span><br><span class="line">		reset-names = &quot;axi&quot;, &quot;ahb&quot;, &quot;dclk&quot;;</span><br><span class="line">		status = &quot;disabled&quot;;</span><br><span class="line"></span><br><span class="line">		vopl_out: port &#123;</span><br><span class="line">				#address-cells = &lt;1&gt;;</span><br><span class="line">				#size-cells = &lt;0&gt;;</span><br><span class="line"></span><br><span class="line">				vopl_out_mipi: endpoint@0 &#123;</span><br><span class="line">						reg = &lt;0&gt;;</span><br><span class="line">						remote-endpoint = &lt;&amp;mipi_in_vopl&gt;;</span><br><span class="line">				&#125;;</span><br><span class="line"></span><br><span class="line">				vopl_out_edp: endpoint@1 &#123;</span><br><span class="line">						reg = &lt;1&gt;;</span><br><span class="line">						remote-endpoint = &lt;&amp;edp_in_vopl&gt;;</span><br><span class="line">				&#125;;</span><br><span class="line"></span><br><span class="line">				vopl_out_hdmi: endpoint@2 &#123;</span><br><span class="line">						reg = &lt;2&gt;;</span><br><span class="line">						remote-endpoint = &lt;&amp;hdmi_in_vopl&gt;;</span><br><span class="line">				&#125;;</span><br><span class="line"></span><br><span class="line">				vopl_out_mipi1: endpoint@3 &#123;</span><br><span class="line">						reg = &lt;3&gt;;</span><br><span class="line">						remote-endpoint = &lt;&amp;mipi1_in_vopl&gt;;</span><br><span class="line">				&#125;;</span><br><span class="line"></span><br><span class="line">				vopl_out_dp: endpoint@4 &#123;</span><br><span class="line">						reg = &lt;4&gt;;</span><br><span class="line">						remote-endpoint = &lt;&amp;dp_in_vopl&gt;;</span><br><span class="line">				&#125;;</span><br><span class="line">		&#125;;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>每个<code>endpoint</code>通过<code>remote-endpoint</code>属性和对应的显示接口组成一个连接通路。设备节点<code>vopb_out</code>同理，这里就不在介绍了。</p>
<h5 id="1-2-1-vopl-out-hdmi"><a href="#1-2-1-vopl-out-hdmi" class="headerlink" title="1.2.1 vopl_out_hdmi"></a>1.2.1 <code>vopl_out_hdmi</code></h5><p><code>vopl_out_hdmi</code>通过<code>hdmi_in_vopl</code>和<code>hdmi</code>显示接口组成一个连接通路；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">hdmi: hdmi@ff940000 &#123;</span><br><span class="line">		compatible = <span class="string">&quot;rockchip,rk3399-dw-hdmi&quot;</span>;</span><br><span class="line">		reg = &lt;<span class="number">0x0</span> <span class="number">0xff940000</span> <span class="number">0x0</span> <span class="number">0x20000</span>&gt;;</span><br><span class="line">		interrupts = &lt;GIC_SPI <span class="number">23</span> IRQ_TYPE_LEVEL_HIGH <span class="number">0</span>&gt;;</span><br><span class="line">		clocks = &lt;&amp;cru PCLK_HDMI_CTRL&gt;,</span><br><span class="line">				 &lt;&amp;cru SCLK_HDMI_SFR&gt;,</span><br><span class="line">				 &lt;&amp;cru SCLK_HDMI_CEC&gt;,</span><br><span class="line">				 &lt;&amp;cru PCLK_VIO_GRF&gt;,</span><br><span class="line">				 &lt;&amp;cru PLL_VPLL&gt;;</span><br><span class="line">		clock-names = <span class="string">&quot;iahb&quot;</span>, <span class="string">&quot;isfr&quot;</span>, <span class="string">&quot;cec&quot;</span>, <span class="string">&quot;grf&quot;</span>, <span class="string">&quot;ref&quot;</span>;</span><br><span class="line">		power-domains = &lt;&amp;power RK3399_PD_HDCP&gt;;</span><br><span class="line">		reg-io-width = &lt;<span class="number">4</span>&gt;;</span><br><span class="line">		rockchip,grf = &lt;&amp;grf&gt;;</span><br><span class="line">		<span class="meta">#sound-dai-cells = <span class="string">&lt;0&gt;</span>;</span></span><br><span class="line">		status = <span class="string">&quot;disabled&quot;</span>;</span><br><span class="line"></span><br><span class="line">		ports &#123;</span><br><span class="line">				hdmi_in: port &#123;</span><br><span class="line">						<span class="meta">#address-cells = <span class="string">&lt;1&gt;</span>;</span></span><br><span class="line">						<span class="meta">#size-cells = <span class="string">&lt;0&gt;</span>;</span></span><br><span class="line"></span><br><span class="line">						hdmi_in_vopb: endpoint@<span class="number">0</span> &#123;</span><br><span class="line">								reg = &lt;<span class="number">0</span>&gt;;</span><br><span class="line">								remote-endpoint = &lt;&amp;vopb_out_hdmi&gt;;</span><br><span class="line">						&#125;;</span><br><span class="line">						hdmi_in_vopl: endpoint@<span class="number">1</span> &#123;</span><br><span class="line">								reg = &lt;<span class="number">1</span>&gt;;</span><br><span class="line">								remote-endpoint = &lt;&amp;vopl_out_hdmi&gt;;</span><br><span class="line">						&#125;;</span><br><span class="line">				&#125;;</span><br><span class="line">		&#125;;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>希望<code>hdmi</code>连接在<code>vopl</code>上，则需要在<code>arch/arm64/boot/dts/rockchip/rk3399-evb.dts</code>中为以下节点新增属性：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">&amp;i2c7 &#123;</span><br><span class="line">        status = <span class="string">&quot;okay&quot;</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&amp;display_subsystem &#123;</span><br><span class="line">         status = <span class="string">&quot;okay&quot;</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&amp;vopl &#123;</span><br><span class="line">        status = <span class="string">&quot;okay&quot;</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&amp;vopl_mmu &#123;</span><br><span class="line">        status = <span class="string">&quot;okay&quot;</span>;</span><br><span class="line">&#125;;</span><br><span class="line">     </span><br><span class="line">&amp;hdmi &#123;</span><br><span class="line">        ddc-i2c-bus = &lt;&amp;i2c7&gt;;</span><br><span class="line">        pinctrl-names = <span class="string">&quot;default&quot;</span>;</span><br><span class="line">        pinctrl<span class="number">-0</span> = &lt;&amp;hdmi_cec&gt;;</span><br><span class="line">        status = <span class="string">&quot;okay&quot;</span>;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h5 id="1-2-2-vopl-out-edp"><a href="#1-2-2-vopl-out-edp" class="headerlink" title="1.2.2 vopl_out_edp"></a>1.2.2 <code>vopl_out_edp</code></h5><p><code>vopl_out_edp</code>通过<code>edp_in_vopl</code>和<code>edp</code>显示接口组成一个连接通路；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">edp: edp@ff970000 &#123;</span><br><span class="line">		compatible = <span class="string">&quot;rockchip,rk3399-edp&quot;</span>;</span><br><span class="line">		reg = &lt;<span class="number">0x0</span> <span class="number">0xff970000</span> <span class="number">0x0</span> <span class="number">0x8000</span>&gt;;</span><br><span class="line">		interrupts = &lt;GIC_SPI <span class="number">10</span> IRQ_TYPE_LEVEL_HIGH <span class="number">0</span>&gt;;</span><br><span class="line">		clocks = &lt;&amp;cru PCLK_EDP&gt;, &lt;&amp;cru PCLK_EDP_CTRL&gt;, &lt;&amp;cru PCLK_VIO_GRF&gt;;</span><br><span class="line">		clock-names = <span class="string">&quot;dp&quot;</span>, <span class="string">&quot;pclk&quot;</span>, <span class="string">&quot;grf&quot;</span>;</span><br><span class="line">		pinctrl-names = <span class="string">&quot;default&quot;</span>;</span><br><span class="line">		pinctrl<span class="number">-0</span> = &lt;&amp;edp_hpd&gt;;</span><br><span class="line">		power-domains = &lt;&amp;power RK3399_PD_EDP&gt;;</span><br><span class="line">		resets = &lt;&amp;cru SRST_P_EDP_CTRL&gt;;</span><br><span class="line">		reset-names = <span class="string">&quot;dp&quot;</span>;</span><br><span class="line">		rockchip,grf = &lt;&amp;grf&gt;;</span><br><span class="line">		status = <span class="string">&quot;disabled&quot;</span>;</span><br><span class="line"></span><br><span class="line">		ports &#123;</span><br><span class="line">				<span class="meta">#address-cells = <span class="string">&lt;1&gt;</span>;</span></span><br><span class="line">				<span class="meta">#size-cells = <span class="string">&lt;0&gt;</span>;</span></span><br><span class="line">				edp_in: port@<span class="number">0</span> &#123;</span><br><span class="line">						reg = &lt;<span class="number">0</span>&gt;;</span><br><span class="line">						<span class="meta">#address-cells = <span class="string">&lt;1&gt;</span>;</span></span><br><span class="line">						<span class="meta">#size-cells = <span class="string">&lt;0&gt;</span>;</span></span><br><span class="line"></span><br><span class="line">						edp_in_vopb: endpoint@<span class="number">0</span> &#123;</span><br><span class="line">								reg = &lt;<span class="number">0</span>&gt;;</span><br><span class="line">								remote-endpoint = &lt;&amp;vopb_out_edp&gt;;</span><br><span class="line">						&#125;;</span><br><span class="line"></span><br><span class="line">						edp_in_vopl: endpoint@<span class="number">1</span> &#123;</span><br><span class="line">								reg = &lt;<span class="number">1</span>&gt;;</span><br><span class="line">								remote-endpoint = &lt;&amp;vopl_out_edp&gt;;</span><br><span class="line">						&#125;;</span><br><span class="line">				&#125;;</span><br><span class="line">		&#125;;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>如果希望<code>edp</code>连接在<code>vopl</code>上，则需要在<code>arch/arm64/boot/dts/rockchip/rk3399-evb.dts</code>中为以下节点新增属性：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">&amp;display_subsystem &#123;</span><br><span class="line">         status = &quot;okay&quot;;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&amp;vopl &#123;</span><br><span class="line">        status = &quot;okay&quot;;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&amp;vopl_mmu &#123;</span><br><span class="line">        status = &quot;okay&quot;;</span><br><span class="line">&#125;;</span><br><span class="line">     </span><br><span class="line">&amp;edp &#123;</span><br><span class="line">        status = &quot;okay&quot;;</span><br><span class="line">        force-hpd;</span><br><span class="line"></span><br><span class="line">        ports &#123;</span><br><span class="line">                edp_out: port@1 &#123;</span><br><span class="line">                        reg = &lt;1&gt;;</span><br><span class="line">                        #address-cells = &lt;1&gt;;</span><br><span class="line">                        #size-cells = &lt;0&gt;;</span><br><span class="line"></span><br><span class="line">                        edp_out_panel: endpoint@0 &#123;</span><br><span class="line">                                reg = &lt;0&gt;;</span><br><span class="line">                                remote-endpoint = &lt;&amp;panel_in_edp&gt;;</span><br><span class="line">                        &#125;;</span><br><span class="line">                &#125;;</span><br><span class="line">        &#125;;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>同时配置设备节点<code>panel_in_edp</code>、<code>backlight</code>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">backlight: backlight &#123;</span><br><span class="line">		compatible = <span class="string">&quot;pwm-backlight&quot;</span>;</span><br><span class="line">		brightness-levels = &lt;</span><br><span class="line">				  <span class="number">0</span>   <span class="number">1</span>   <span class="number">2</span>   <span class="number">3</span>   <span class="number">4</span>   <span class="number">5</span>   <span class="number">6</span>   <span class="number">7</span></span><br><span class="line">				  <span class="number">8</span>   <span class="number">9</span>  <span class="number">10</span>  <span class="number">11</span>  <span class="number">12</span>  <span class="number">13</span>  <span class="number">14</span>  <span class="number">15</span></span><br><span class="line">				 <span class="number">16</span>  <span class="number">17</span>  <span class="number">18</span>  <span class="number">19</span>  <span class="number">20</span>  <span class="number">21</span>  <span class="number">22</span>  <span class="number">23</span></span><br><span class="line">				 <span class="number">24</span>  <span class="number">25</span>  <span class="number">26</span>  <span class="number">27</span>  <span class="number">28</span>  <span class="number">29</span>  <span class="number">30</span>  <span class="number">31</span></span><br><span class="line">				 <span class="number">32</span>  <span class="number">33</span>  <span class="number">34</span>  <span class="number">35</span>  <span class="number">36</span>  <span class="number">37</span>  <span class="number">38</span>  <span class="number">39</span></span><br><span class="line">				 <span class="number">40</span>  <span class="number">41</span>  <span class="number">42</span>  <span class="number">43</span>  <span class="number">44</span>  <span class="number">45</span>  <span class="number">46</span>  <span class="number">47</span></span><br><span class="line">				 <span class="number">48</span>  <span class="number">49</span>  <span class="number">50</span>  <span class="number">51</span>  <span class="number">52</span>  <span class="number">53</span>  <span class="number">54</span>  <span class="number">55</span></span><br><span class="line">				 <span class="number">56</span>  <span class="number">57</span>  <span class="number">58</span>  <span class="number">59</span>  <span class="number">60</span>  <span class="number">61</span>  <span class="number">62</span>  <span class="number">63</span></span><br><span class="line">				 <span class="number">64</span>  <span class="number">65</span>  <span class="number">66</span>  <span class="number">67</span>  <span class="number">68</span>  <span class="number">69</span>  <span class="number">70</span>  <span class="number">71</span></span><br><span class="line">				 <span class="number">72</span>  <span class="number">73</span>  <span class="number">74</span>  <span class="number">75</span>  <span class="number">76</span>  <span class="number">77</span>  <span class="number">78</span>  <span class="number">79</span></span><br><span class="line">				 <span class="number">80</span>  <span class="number">81</span>  <span class="number">82</span>  <span class="number">83</span>  <span class="number">84</span>  <span class="number">85</span>  <span class="number">86</span>  <span class="number">87</span></span><br><span class="line">				 <span class="number">88</span>  <span class="number">89</span>  <span class="number">90</span>  <span class="number">91</span>  <span class="number">92</span>  <span class="number">93</span>  <span class="number">94</span>  <span class="number">95</span></span><br><span class="line">				 <span class="number">96</span>  <span class="number">97</span>  <span class="number">98</span>  <span class="number">99</span> <span class="number">100</span> <span class="number">101</span> <span class="number">102</span> <span class="number">103</span></span><br><span class="line">				<span class="number">104</span> <span class="number">105</span> <span class="number">106</span> <span class="number">107</span> <span class="number">108</span> <span class="number">109</span> <span class="number">110</span> <span class="number">111</span></span><br><span class="line">				<span class="number">112</span> <span class="number">113</span> <span class="number">114</span> <span class="number">115</span> <span class="number">116</span> <span class="number">117</span> <span class="number">118</span> <span class="number">119</span></span><br><span class="line">				<span class="number">120</span> <span class="number">121</span> <span class="number">122</span> <span class="number">123</span> <span class="number">124</span> <span class="number">125</span> <span class="number">126</span> <span class="number">127</span></span><br><span class="line">				<span class="number">128</span> <span class="number">129</span> <span class="number">130</span> <span class="number">131</span> <span class="number">132</span> <span class="number">133</span> <span class="number">134</span> <span class="number">135</span></span><br><span class="line">				<span class="number">136</span> <span class="number">137</span> <span class="number">138</span> <span class="number">139</span> <span class="number">140</span> <span class="number">141</span> <span class="number">142</span> <span class="number">143</span></span><br><span class="line">				<span class="number">144</span> <span class="number">145</span> <span class="number">146</span> <span class="number">147</span> <span class="number">148</span> <span class="number">149</span> <span class="number">150</span> <span class="number">151</span></span><br><span class="line">				<span class="number">152</span> <span class="number">153</span> <span class="number">154</span> <span class="number">155</span> <span class="number">156</span> <span class="number">157</span> <span class="number">158</span> <span class="number">159</span></span><br><span class="line">				<span class="number">160</span> <span class="number">161</span> <span class="number">162</span> <span class="number">163</span> <span class="number">164</span> <span class="number">165</span> <span class="number">166</span> <span class="number">167</span></span><br><span class="line">				<span class="number">168</span> <span class="number">169</span> <span class="number">170</span> <span class="number">171</span> <span class="number">172</span> <span class="number">173</span> <span class="number">174</span> <span class="number">175</span></span><br><span class="line">				<span class="number">176</span> <span class="number">177</span> <span class="number">178</span> <span class="number">179</span> <span class="number">180</span> <span class="number">181</span> <span class="number">182</span> <span class="number">183</span></span><br><span class="line">				<span class="number">184</span> <span class="number">185</span> <span class="number">186</span> <span class="number">187</span> <span class="number">188</span> <span class="number">189</span> <span class="number">190</span> <span class="number">191</span></span><br><span class="line">				<span class="number">192</span> <span class="number">193</span> <span class="number">194</span> <span class="number">195</span> <span class="number">196</span> <span class="number">197</span> <span class="number">198</span> <span class="number">199</span></span><br><span class="line">				<span class="number">200</span> <span class="number">201</span> <span class="number">202</span> <span class="number">203</span> <span class="number">204</span> <span class="number">205</span> <span class="number">206</span> <span class="number">207</span></span><br><span class="line">				<span class="number">208</span> <span class="number">209</span> <span class="number">210</span> <span class="number">211</span> <span class="number">212</span> <span class="number">213</span> <span class="number">214</span> <span class="number">215</span></span><br><span class="line">				<span class="number">216</span> <span class="number">217</span> <span class="number">218</span> <span class="number">219</span> <span class="number">220</span> <span class="number">221</span> <span class="number">222</span> <span class="number">223</span></span><br><span class="line">				<span class="number">224</span> <span class="number">225</span> <span class="number">226</span> <span class="number">227</span> <span class="number">228</span> <span class="number">229</span> <span class="number">230</span> <span class="number">231</span></span><br><span class="line">				<span class="number">232</span> <span class="number">233</span> <span class="number">234</span> <span class="number">235</span> <span class="number">236</span> <span class="number">237</span> <span class="number">238</span> <span class="number">239</span></span><br><span class="line">				<span class="number">240</span> <span class="number">241</span> <span class="number">242</span> <span class="number">243</span> <span class="number">244</span> <span class="number">245</span> <span class="number">246</span> <span class="number">247</span></span><br><span class="line">				<span class="number">248</span> <span class="number">249</span> <span class="number">250</span> <span class="number">251</span> <span class="number">252</span> <span class="number">253</span> <span class="number">254</span> <span class="number">255</span>&gt;;</span><br><span class="line">		<span class="keyword">default</span>-brightness-level = &lt;<span class="number">200</span>&gt;;</span><br><span class="line">		pwms = &lt;&amp;pwm0 <span class="number">0</span> <span class="number">25000</span> <span class="number">0</span>&gt;;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">edp_panel: edp-panel &#123;</span><br><span class="line">		compatible = <span class="string">&quot;lg,lp079qx1-sp0v&quot;</span>;</span><br><span class="line">		backlight = &lt;&amp;backlight&gt;;</span><br><span class="line">		enable-gpios = &lt;&amp;gpio1 RK_PB5 GPIO_ACTIVE_HIGH&gt;;</span><br><span class="line">		power-supply = &lt;&amp;vcc3v3_s0&gt;;</span><br><span class="line"></span><br><span class="line">		port &#123;</span><br><span class="line">				panel_in_edp: endpoint &#123;</span><br><span class="line">						remote-endpoint = &lt;&amp;edp_out_panel&gt;;</span><br><span class="line">				&#125;;</span><br><span class="line">		&#125;;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h3 id="二、rockchip-drm-driver"><a href="#二、rockchip-drm-driver" class="headerlink" title="二、rockchip_drm_driver"></a>二、<code>rockchip_drm_driver</code></h3><p>这里我们以<code>RK3399 DRM</code>驱动为例进行介绍：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">root@zhengyang:/work/sambashare/rk3399/linux-6.3# ll drivers/gpu/drm/rockchip/rockchip_drm*.c</span><br><span class="line">-rw-rw-r-- 1 root root 13006 Jun 13 20:29 drivers/gpu/drm/rockchip/rockchip_drm_drv.c</span><br><span class="line">-rw-rw-r-- 1 root root  2460 Apr 24 03:02 drivers/gpu/drm/rockchip/rockchip_drm_fb.c</span><br><span class="line">-rw-rw-r-- 1 root root 13430 Apr 24 03:02 drivers/gpu/drm/rockchip/rockchip_drm_gem.c</span><br><span class="line">-rw-rw-r-- 1 root root 80149 Apr 24 03:02 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c</span><br><span class="line">-rw-rw-r-- 1 root root 60878 Apr 24 03:02 drivers/gpu/drm/rockchip/rockchip_drm_vop.c</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>其中：</p>
<ul>
<li><code>rockchip_drm_drv.c</code>：实现了<code>DRM</code>驱动；</li>
<li><code>rockchip_drm_fb.c</code>：实现了<code>framebuffer</code>驱动；</li>
<li><code>rockchip_drm_gem.c</code>：实现了<code>gem</code>驱动， 主要负责显示<code>buffer</code>的分配和释放；</li>
</ul>
<p>下面我们以源码<code>rockchip_drm_drv.c</code>中的<code>rockchip_drm_driver</code>全局变量作为切入点进行介绍；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">drm_driver</span> <span class="title">rockchip_drm_driver</span> =</span> &#123;</span><br><span class="line">        .driver_features        = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,</span><br><span class="line">        .dumb_create            = rockchip_gem_dumb_create,</span><br><span class="line">        .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,</span><br><span class="line">        .prime_fd_to_handle     = drm_gem_prime_fd_to_handle,</span><br><span class="line">        .gem_prime_import_sg_table      = rockchip_gem_prime_import_sg_table,</span><br><span class="line">        .gem_prime_mmap         = drm_gem_prime_mmap,</span><br><span class="line">        .fops                   = &amp;rockchip_drm_driver_fops,</span><br><span class="line">        .name   = DRIVER_NAME,</span><br><span class="line">        .desc   = DRIVER_DESC,</span><br><span class="line">        .date   = DRIVER_DATE,</span><br><span class="line">        .major  = DRIVER_MAJOR,</span><br><span class="line">        .minor  = DRIVER_MINOR,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h4 id="2-1-driver-features"><a href="#2-1-driver-features" class="headerlink" title="2.1 driver_features"></a>2.1 <code>driver_features</code></h4><ul>
<li>添加上 <code>DRIVER_GEM</code> 标志位，告诉<code>DRM Core</code>该驱动支持<code>GEM</code>操作；</li>
<li>添加上 <code>DRIVER_MODESET</code> 标志位，告诉<code>DRM Core</code> 该驱动支持<code>kernel Mode Setting</code>操作；</li>
<li>添加上 <code>DRIVER_ATOMIC</code> 标志位，告诉 <code>DRM Core</code>该驱动支持<code>Atomic</code>操作。</li>
</ul>
<h4 id="2-2-宏变量"><a href="#2-2-宏变量" class="headerlink" title="2.2 宏变量"></a>2.2 宏变量</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> DRIVER_NAME     <span class="string">&quot;rockchip&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DRIVER_DESC     <span class="string">&quot;RockChip Soc DRM&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DRIVER_DATE     <span class="string">&quot;20140818&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DRIVER_MAJOR    1</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DRIVER_MINOR    0</span></span><br></pre></td></tr></table></figure>

<h3 id="三、dumb-create"><a href="#三、dumb-create" class="headerlink" title="三、dumb_create"></a>三、<code>dumb_create</code></h3><p>其中<code>dumb_create</code>配置为<code>rockchip_gem_dumb_create</code>，该函数用于分配物理内存<code>dumb buffer</code>，函数定义在<code>drivers/gpu/drm/rockchip/rockchip_drm_gem.c</code>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * rockchip_gem_dumb_create - (struct drm_driver)-&gt;dumb_create callback</span></span><br><span class="line"><span class="comment"> * function</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This aligns the pitch and size arguments to the minimum required. wrap</span></span><br><span class="line"><span class="comment"> * this into your own function if you need bigger alignment.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">rockchip_gem_dumb_create</span><span class="params">(<span class="keyword">struct</span> drm_file *file_priv,</span></span><br><span class="line"><span class="params">                             <span class="keyword">struct</span> drm_device *dev,</span></span><br><span class="line"><span class="params">                             <span class="keyword">struct</span> drm_mode_create_dumb *args)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">rockchip_gem_object</span> *<span class="title">rk_obj</span>;</span></span><br><span class="line">		</span><br><span class="line">		<span class="comment">// 宽度*每像素位数/8</span></span><br><span class="line">        <span class="type">int</span> min_pitch = DIV_ROUND_UP(args-&gt;width * args-&gt;bpp, <span class="number">8</span>);  </span><br><span class="line"></span><br><span class="line">        <span class="comment">/*</span></span><br><span class="line"><span class="comment">         * align to 64 bytes since Mali requires it.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        args-&gt;pitch = ALIGN(min_pitch, <span class="number">64</span>);</span><br><span class="line">		</span><br><span class="line">		<span class="comment">// 宽*高*每像素位数/8，即得到总大小（单位字节）</span></span><br><span class="line">        args-&gt;size = args-&gt;pitch * args-&gt;height;  </span><br><span class="line"></span><br><span class="line">        rk_obj = rockchip_gem_create_with_handle(file_priv, dev, args-&gt;size,</span><br><span class="line">                                                 &amp;args-&gt;handle);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> PTR_ERR_OR_ZERO(rk_obj);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这里主要实现函数是<code>rockchip_gem_create_with_handle</code>，定义如下；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * rockchip_gem_create_with_handle - allocate an object with the given</span></span><br><span class="line"><span class="comment"> * size and create a gem handle on it</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * returns a struct rockchip_gem_object* on success or ERR_PTR values</span></span><br><span class="line"><span class="comment"> * on failure.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">struct</span> rockchip_gem_object *</span><br><span class="line"><span class="title function_">rockchip_gem_create_with_handle</span><span class="params">(<span class="keyword">struct</span> drm_file *file_priv,</span></span><br><span class="line"><span class="params">                                <span class="keyword">struct</span> drm_device *drm, <span class="type">unsigned</span> <span class="type">int</span> size,</span></span><br><span class="line"><span class="params">                                <span class="type">unsigned</span> <span class="type">int</span> *handle)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">rockchip_gem_object</span> *<span class="title">rk_obj</span>;</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_gem_object</span> *<span class="title">obj</span>;</span></span><br><span class="line">        <span class="type">bool</span> is_framebuffer;</span><br><span class="line">        <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">        is_framebuffer = drm-&gt;fb_helper &amp;&amp; file_priv == drm-&gt;fb_helper-&gt;client.file;</span><br><span class="line"></span><br><span class="line">        rk_obj = rockchip_gem_create_object(drm, size, is_framebuffer);</span><br><span class="line">        <span class="keyword">if</span> (IS_ERR(rk_obj))</span><br><span class="line">                <span class="keyword">return</span> ERR_CAST(rk_obj);</span><br><span class="line"></span><br><span class="line">		<span class="comment">// 获取GEM对象</span></span><br><span class="line">        obj = &amp;rk_obj-&gt;base; </span><br><span class="line"></span><br><span class="line">        <span class="comment">/*</span></span><br><span class="line"><span class="comment">         * allocate a id of idr table where the obj is registered</span></span><br><span class="line"><span class="comment">         * and handle has the id what user can see.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        ret = drm_gem_handle_create(file_priv, obj, handle); </span><br><span class="line">        <span class="keyword">if</span> (ret)</span><br><span class="line">                <span class="keyword">goto</span> err_handle_create;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* drop reference from allocate - handle holds it now. */</span></span><br><span class="line">        drm_gem_object_put(obj);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> rk_obj;</span><br><span class="line"></span><br><span class="line">err_handle_create:</span><br><span class="line">        rockchip_gem_free_object(obj);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> ERR_PTR(ret);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>函数执行流程如下：</p>
<p>(1) 调用<code>rockchip_gem_create_object</code>创建并初始化<code>Rockchip</code>驱动自定义的<code>GEM</code>对象<code>struct rockchip_gem_objec</code>；</p>
<p>数据结构<code>rockchip_gem_object</code>是<code>Rockchip</code>驱动自定义的<code>GEM</code>对象，内部包含<code> struct drm_gem_object</code>，定义在<code>drivers/gpu/drm/rockchip/rockchip_drm_gem.h</code>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rockchip_gem_object</span> &#123;</span>             <span class="comment">// Rockchip私有的GEM对象 </span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_gem_object</span> <span class="title">base</span>;</span>      <span class="comment">// GEM对象</span></span><br><span class="line">        <span class="type">unsigned</span> <span class="type">int</span> flags;</span><br><span class="line"></span><br><span class="line">        <span class="type">void</span> *kvaddr;</span><br><span class="line">        <span class="type">dma_addr_t</span> dma_addr;             <span class="comment">// dma地址   </span></span><br><span class="line">        <span class="comment">/* Used when IOMMU is disabled */</span></span><br><span class="line">        <span class="type">unsigned</span> <span class="type">long</span> dma_attrs;         <span class="comment">// dma buffer虚拟地址   </span></span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Used when IOMMU is enabled */</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_mm_node</span> <span class="title">mm</span>;</span></span><br><span class="line">        <span class="type">unsigned</span> <span class="type">long</span> num_pages;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">page</span> **<span class="title">pages</span>;</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">sg_table</span> *<span class="title">sgt</span>;</span></span><br><span class="line">        <span class="type">size_t</span> size;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>(2) 调用<code>drm_gem_handle_create</code>创建<code>GEM</code>对象<code>handle</code>；</p>
<p>(3) 调用<code>drm_gem_object_put</code>将<code>GEM</code>对象的引用计数-1；</p>
<p><code>rockchip_gem_create_with_handle</code>函数调用栈：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">rockchip_gem_create_with_handle(file_priv, dev, args-&gt;size,&amp;args-&gt;handle)</span><br><span class="line">    <span class="comment">// #1 创建并初始化Rockchip驱动自定义的GEM对象</span></span><br><span class="line">    rockchip_gem_create_object(drm, size, is_framebuffer) </span><br><span class="line">	    <span class="comment">// #1.1 创建Rockchip驱动自定义的GEM对象 </span></span><br><span class="line">    	rockchip_gem_alloc_object(drm, size)          </span><br><span class="line">		    <span class="comment">// GEM对象初始化</span></span><br><span class="line">    		drm_gem_object_init(drm, obj, size)       </span><br><span class="line">	    <span class="comment">// #1.2 为Rockchip GEM对象分配DMA缓冲区，或者在IOMMU上分配内存</span></span><br><span class="line"> 	    rockchip_gem_alloc_buf(rk_obj, alloc_kmap)    </span><br><span class="line">			rockchip_gem_alloc_dma(rk_obj, alloc_kmap)    <span class="comment">// </span></span><br><span class="line">    <span class="comment">// #2 创建GEM对象handle</span></span><br><span class="line">    drm_gem_handle_create(file_priv, obj, handle)    </span><br><span class="line">    <span class="comment">// 3# 引用计数-1</span></span><br><span class="line">    drm_gem_object_put(obj) </span><br></pre></td></tr></table></figure>

<h4 id="3-1-rockchip-gem-create-object"><a href="#3-1-rockchip-gem-create-object" class="headerlink" title="3.1  rockchip_gem_create_object"></a>3.1  <code>rockchip_gem_create_object</code></h4><p><code>rockchip_gem_create_object</code>函数定义在<code>drivers/gpu/drm/rockchip/rockchip_drm_gem.c</code>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> rockchip_gem_object *</span><br><span class="line"><span class="title function_">rockchip_gem_create_object</span><span class="params">(<span class="keyword">struct</span> drm_device *drm, <span class="type">unsigned</span> <span class="type">int</span> size,</span></span><br><span class="line"><span class="params">                           <span class="type">bool</span> alloc_kmap)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">rockchip_gem_object</span> *<span class="title">rk_obj</span>;</span></span><br><span class="line">        <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 创建Rockchip驱动自定义的GEM对象 </span></span><br><span class="line">        rk_obj = rockchip_gem_alloc_object(drm, size); </span><br><span class="line">        <span class="keyword">if</span> (IS_ERR(rk_obj))</span><br><span class="line">                <span class="keyword">return</span> rk_obj;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 为Rockchip GEM对象分配DMA缓冲区，或者在IOMMU上分配内存</span></span><br><span class="line">        ret = rockchip_gem_alloc_buf(rk_obj, alloc_kmap);</span><br><span class="line">        <span class="keyword">if</span> (ret)</span><br><span class="line">                <span class="keyword">goto</span> err_free_rk_obj;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> rk_obj;</span><br><span class="line"></span><br><span class="line">err_free_rk_obj:</span><br><span class="line">        rockchip_gem_release_object(rk_obj);</span><br><span class="line">        <span class="keyword">return</span> ERR_PTR(ret);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="3-1-2-rockchip-gem-alloc-object"><a href="#3-1-2-rockchip-gem-alloc-object" class="headerlink" title="3.1.2 rockchip_gem_alloc_object"></a>3.1.2 <code>rockchip_gem_alloc_object</code></h5><p><code>rockchip_gem_alloc_object</code>用于创建<code>Rockchip</code>驱动自定义的<code>GEM</code>对象；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">drm_gem_object_funcs</span> <span class="title">rockchip_gem_object_funcs</span> =</span> &#123;</span><br><span class="line">		 <span class="comment">// 释放GEM对象及其相关资源的操作</span></span><br><span class="line">        .<span class="built_in">free</span> = rockchip_gem_free_object,</span><br><span class="line">        .get_sg_table = rockchip_gem_prime_get_sg_table,</span><br><span class="line">        .vmap = rockchip_gem_prime_vmap,</span><br><span class="line">        .vunmap = rockchip_gem_prime_vunmap,</span><br><span class="line">        .mmap = rockchip_drm_gem_object_mmap,</span><br><span class="line">        .vm_ops = &amp;drm_gem_dma_vm_ops,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="keyword">struct</span> rockchip_gem_object *</span><br><span class="line">        <span class="title function_">rockchip_gem_alloc_object</span><span class="params">(<span class="keyword">struct</span> drm_device *drm, <span class="type">unsigned</span> <span class="type">int</span> size)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">rockchip_gem_object</span> *<span class="title">rk_obj</span>;</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_gem_object</span> *<span class="title">obj</span>;</span></span><br><span class="line"></span><br><span class="line">        size = round_up(size, PAGE_SIZE);</span><br><span class="line"></span><br><span class="line">        rk_obj = kzalloc(<span class="keyword">sizeof</span>(*rk_obj), GFP_KERNEL);</span><br><span class="line">        <span class="keyword">if</span> (!rk_obj)</span><br><span class="line">                <span class="keyword">return</span> ERR_PTR(-ENOMEM);</span><br><span class="line"></span><br><span class="line">        obj = &amp;rk_obj-&gt;base;</span><br><span class="line"></span><br><span class="line">        obj-&gt;funcs = &amp;rockchip_gem_object_funcs;</span><br><span class="line"></span><br><span class="line">        drm_gem_object_init(drm, obj, size);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> rk_obj;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>流程如此：</p>
<ul>
<li>调用<code>kzalloc</code>动态分配<code>Rockchip </code>驱动自定义的<code>GEM</code>对象 <code>struct rockchip_gem_object</code>；</li>
<li>然后设定<code>GEM</code>对象<code>funcs</code>为<code>rockchip_gem_object_funcs</code>；</li>
<li>最后调用<code>drm_gem_object_init</code>初始化<code>GEM</code>对象，创建一个大小为<code>size</code>的<code>shmfs</code>，并将这个<code>shmfs file</code>存放到<code>struct drm_gem_object</code>的<code>filp</code>字段。</li>
</ul>
<h5 id="3-1-2-rockchip-gem-alloc-buf"><a href="#3-1-2-rockchip-gem-alloc-buf" class="headerlink" title="3.1.2 rockchip_gem_alloc_buf"></a>3.1.2 <code>rockchip_gem_alloc_buf</code></h5><p><code>rockchip_gem_alloc_buf</code>函数用于为<code>Rockchip GEM</code>对象分配<code>DMA</code>缓冲区，或者在<code>IOMMU</code>上分配内存；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rockchip_gem_alloc_buf</span><span class="params">(<span class="keyword">struct</span> rockchip_gem_object *rk_obj,</span></span><br><span class="line"><span class="params">                                  <span class="type">bool</span> alloc_kmap)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_gem_object</span> *<span class="title">obj</span> =</span> &amp;rk_obj-&gt;base;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">drm</span> =</span> obj-&gt;dev;</span><br><span class="line">	    <span class="comment">// 获取drm驱动私有数据</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">rockchip_drm_private</span> *<span class="title">private</span> =</span> drm-&gt;dev_private; </span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (private-&gt;domain)</span><br><span class="line">                <span class="comment">// 为Rockchip GEM对象在IOMMU上分配内存</span></span><br><span class="line">                <span class="keyword">return</span> rockchip_gem_alloc_iommu(rk_obj, alloc_kmap);</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">            	<span class="comment">// 为Rockchip GEM对象分配DMA缓冲区</span></span><br><span class="line">                <span class="keyword">return</span> rockchip_gem_alloc_dma(rk_obj, alloc_kmap);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>由于没有初始化<code>private-&gt;domain</code>，因此会执行<code>rockchip_gem_alloc_dma</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rockchip_gem_alloc_iommu</span><span class="params">(<span class="keyword">struct</span> rockchip_gem_object *rk_obj,</span></span><br><span class="line"><span class="params">                                    <span class="type">bool</span> alloc_kmap)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">		<span class="comment">// 获取页面</span></span><br><span class="line">        ret = rockchip_gem_get_pages(rk_obj);  </span><br><span class="line">        <span class="keyword">if</span> (ret &lt; <span class="number">0</span>)</span><br><span class="line">                <span class="keyword">return</span> ret;</span><br><span class="line"></span><br><span class="line">		<span class="comment">// 将GEM对象映射到IOMMU</span></span><br><span class="line">        ret = rockchip_gem_iommu_map(rk_obj); </span><br><span class="line">        <span class="keyword">if</span> (ret &lt; <span class="number">0</span>)</span><br><span class="line">                <span class="keyword">goto</span> err_free;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (alloc_kmap) &#123;</span><br><span class="line">                <span class="comment">// 将获取到的页面映射到内核虚拟地址空间中</span></span><br><span class="line">                rk_obj-&gt;kvaddr = vmap(rk_obj-&gt;pages, rk_obj-&gt;num_pages, VM_MAP,</span><br><span class="line">                                      pgprot_writecombine(PAGE_KERNEL));</span><br><span class="line">                <span class="keyword">if</span> (!rk_obj-&gt;kvaddr) &#123;</span><br><span class="line">                        DRM_ERROR(<span class="string">&quot;failed to vmap() buffer\n&quot;</span>);</span><br><span class="line">                        ret = -ENOMEM;</span><br><span class="line">                        <span class="keyword">goto</span> err_unmap;</span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">err_unmap:</span><br><span class="line">    	<span class="comment">// 解除IOMMU映射</span></span><br><span class="line">        rockchip_gem_iommu_unmap(rk_obj);</span><br><span class="line">err_free:</span><br><span class="line">        <span class="comment">// 释放页面</span></span><br><span class="line">        rockchip_gem_put_pages(rk_obj);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rockchip_gem_alloc_dma</span><span class="params">(<span class="keyword">struct</span> rockchip_gem_object *rk_obj,</span></span><br><span class="line"><span class="params">                                  <span class="type">bool</span> alloc_kmap)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_gem_object</span> *<span class="title">obj</span> =</span> &amp;rk_obj-&gt;base;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">drm</span> =</span> obj-&gt;dev;</span><br><span class="line"></span><br><span class="line">        rk_obj-&gt;dma_attrs = DMA_ATTR_WRITE_COMBINE;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!alloc_kmap)</span><br><span class="line">                rk_obj-&gt;dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 分配DMA缓冲区。分配的大小为obj-&gt;size字节，属性为rk_obj-&gt;dma_attrs</span></span><br><span class="line">        rk_obj-&gt;kvaddr = dma_alloc_attrs(drm-&gt;dev, obj-&gt;size,</span><br><span class="line">                                         &amp;rk_obj-&gt;dma_addr, GFP_KERNEL,</span><br><span class="line">                                         rk_obj-&gt;dma_attrs);</span><br><span class="line">        <span class="keyword">if</span> (!rk_obj-&gt;kvaddr) &#123;</span><br><span class="line">                DRM_ERROR(<span class="string">&quot;failed to allocate %zu byte dma buffer&quot;</span>, obj-&gt;size);</span><br><span class="line">                <span class="keyword">return</span> -ENOMEM;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="四、DRM设备节点文件操作集"><a href="#四、DRM设备节点文件操作集" class="headerlink" title="四、DRM设备节点文件操作集"></a>四、<code>DRM</code>设备节点文件操作集</h3><p><code>DRM</code>驱动程序必须定义文件操作结构，形成<code>DRM</code>用户空间<code>API</code>的入口点，在<code>rockchip_drm_driver</code>中将<code>DRM</code>设备节点文件操作集<code>fops</code>设置为<code>rockchip_drm_driver_fops</code>，内容如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">DEFINE_DRM_GEM_FOPS(rockchip_drm_driver_fops);</span><br></pre></td></tr></table></figure>

<p><code>DEFINE_DRM_GEM_FOPS</code>宏定义在<code>include/drm/drm_gem.h</code>：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * DRM_GEM_FOPS - Default drm GEM file operations</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This macro provides a shorthand for setting the GEM file ops in the</span></span><br><span class="line"><span class="comment"> * &amp;file_operations structure.  If all you need are the default ops, use</span></span><br><span class="line"><span class="comment"> * DEFINE_DRM_GEM_FOPS instead.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DRM_GEM_FOPS \</span></span><br><span class="line"><span class="meta">        .open           = drm_open,\</span></span><br><span class="line"><span class="meta">        .release        = drm_release,\</span></span><br><span class="line"><span class="meta">        .unlocked_ioctl = drm_ioctl,\</span></span><br><span class="line"><span class="meta">        .compat_ioctl   = drm_compat_ioctl,\</span></span><br><span class="line"><span class="meta">        .poll           = drm_poll,\</span></span><br><span class="line"><span class="meta">        .read           = drm_read,\</span></span><br><span class="line"><span class="meta">        .llseek         = noop_llseek,\</span></span><br><span class="line"><span class="meta">        .mmap           = drm_gem_mmap</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * DEFINE_DRM_GEM_FOPS() - macro to generate file operations for GEM drivers</span></span><br><span class="line"><span class="comment"> * @name: name for the generated structure</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This macro autogenerates a suitable &amp;struct file_operations for GEM based</span></span><br><span class="line"><span class="comment"> * drivers, which can be assigned to &amp;drm_driver.fops. Note that this structure</span></span><br><span class="line"><span class="comment"> * cannot be shared between drivers, because it contains a reference to the</span></span><br><span class="line"><span class="comment"> * current module using THIS_MODULE.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Note that the declaration is already marked as static - if you need a</span></span><br><span class="line"><span class="comment"> * non-static version of this you&#x27;re probably doing it wrong and will break the</span></span><br><span class="line"><span class="comment"> * THIS_MODULE reference by accident.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DEFINE_DRM_GEM_FOPS(name) \</span></span><br><span class="line"><span class="meta">        static const struct file_operations name = &#123;\</span></span><br><span class="line"><span class="meta">                .owner          = THIS_MODULE,\</span></span><br><span class="line"><span class="meta">                DRM_GEM_FOPS,\</span></span><br><span class="line"><span class="meta">        &#125;</span></span><br></pre></td></tr></table></figure>

<p>宏展开后得到：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">rockchip_drm_driver_fops</span> =</span> &#123;</span><br><span class="line">		.owner          = THIS_MODULE,</span><br><span class="line">        .open           = drm_open,</span><br><span class="line">        .release        = drm_release,</span><br><span class="line">        .unlocked_ioctl = drm_ioctl,</span><br><span class="line">        .compat_ioctl   = drm_compat_ioctl,</span><br><span class="line">        .poll           = drm_poll,</span><br><span class="line">        .read           = drm_read,</span><br><span class="line">        .llseek         = noop_llseek,</span><br><span class="line">        .mmap           = drm_gem_mmap</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>强制要求的函数是<code>drm_open</code>、<code>drm_read</code>、<code>drm_ioctl</code>和<code>drm_compat_ioctl</code>（如果启用了<code>CONFIG_COMPAT</code>）；<br><code>drm_read</code>和<code>drm_poll</code>提供了对<code>DRM</code>事件的支持。<code>DRM</code>事件是一种通用且可扩展的方式，通过文件描述符向用户空间发送异步事件。它们用于通过<code>KMS API</code>发送<code>vblank</code>事件和页面翻转完成事件。但是驱动程序也可以根据自己的需求使用它，例如用于信号渲染完成。<br>内存映射的实现方式将根据驱动程序如何管理内存而有所不同：</p>
<ul>
<li>过时驱动程序将使用<code>drm_legacy_mmap</code>函数；</li>
<li>现代驱动程序应该使用提供的特定于内存管理器的实现之一；对于基于<code>GEM</code>的驱动程序，可以使用<code>drm_gem_mmap</code>。</li>
</ul>
<h4 id="4-1-drm-open"><a href="#4-1-drm-open" class="headerlink" title="4.1 drm_open"></a>4.1 <code>drm_open</code></h4><p>在上一篇博客中，我们说过当打开一个<code>drm</code>设备时，比如<code>/dev/dri/card0</code>，最终回调用<code>drm driver</code>的文件操作集<code>fops</code>中的<code>open</code>函数，即<code>drm_open</code>；<code>drm_open</code>函数定义在<code>drivers/gpu/drm/drm_file.c</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * drm_open - open method for DRM file</span></span><br><span class="line"><span class="comment"> * @inode: device inode</span></span><br><span class="line"><span class="comment"> * @filp: file pointer.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This function must be used by drivers as their &amp;file_operations.open method.</span></span><br><span class="line"><span class="comment"> * It looks up the correct DRM device and instantiates all the per-file</span></span><br><span class="line"><span class="comment"> * resources for it. It also calls the &amp;drm_driver.open driver callback.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * RETURNS:</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * 0 on success or negative errno value on failure.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">drm_open</span><span class="params">(<span class="keyword">struct</span> inode *inode, <span class="keyword">struct</span> file *filp)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span>;</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_minor</span> *<span class="title">minor</span>;</span></span><br><span class="line">        <span class="type">int</span> retcode;</span><br><span class="line">        <span class="type">int</span> need_setup = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 根据设备节点获取struct drm_minor</span></span><br><span class="line">        minor = drm_minor_acquire(iminor(inode));</span><br><span class="line">        <span class="keyword">if</span> (IS_ERR(minor))</span><br><span class="line">                <span class="keyword">return</span> PTR_ERR(minor);</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 获取drm device</span></span><br><span class="line">        dev = minor-&gt;dev;</span><br><span class="line">        <span class="keyword">if</span> (drm_dev_needs_global_mutex(dev))</span><br><span class="line">                mutex_lock(&amp;drm_global_mutex);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!atomic_fetch_inc(&amp;dev-&gt;open_count))</span><br><span class="line">                need_setup = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* share address_space across all char-devs of a single device */</span></span><br><span class="line">        filp-&gt;f_mapping = dev-&gt;anon_inode-&gt;i_mapping;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 调用drm open helper函数</span></span><br><span class="line">        retcode = drm_open_helper(filp, minor);</span><br><span class="line">        <span class="keyword">if</span> (retcode)</span><br><span class="line">                <span class="keyword">goto</span> err_undo;</span><br><span class="line">        <span class="keyword">if</span> (need_setup) &#123;</span><br><span class="line">                retcode = drm_legacy_setup(dev);</span><br><span class="line">                <span class="keyword">if</span> (retcode) &#123;</span><br><span class="line">                        drm_close_helper(filp);</span><br><span class="line">                        <span class="keyword">goto</span> err_undo;</span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (drm_dev_needs_global_mutex(dev))</span><br><span class="line">                mutex_unlock(&amp;drm_global_mutex);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">err_undo:</span><br><span class="line">        <span class="type">atomic_dec</span>(&amp;dev-&gt;open_count);</span><br><span class="line">        <span class="keyword">if</span> (drm_dev_needs_global_mutex(dev))</span><br><span class="line">                mutex_unlock(&amp;drm_global_mutex);</span><br><span class="line">        drm_minor_release(minor);</span><br><span class="line">        <span class="keyword">return</span> retcode;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这里核心实现为<code>drm_open_helper</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Called whenever a process opens a drm node</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * \param filp file pointer.</span></span><br><span class="line"><span class="comment"> * \param minor acquired minor-object.</span></span><br><span class="line"><span class="comment"> * \return zero on success or a negative number on failure.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Creates and initializes a drm_file structure for the file private data in \p</span></span><br><span class="line"><span class="comment"> * filp and add it into the double linked list in \p dev.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">drm_open_helper</span><span class="params">(<span class="keyword">struct</span> file *filp, <span class="keyword">struct</span> drm_minor *minor)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span> =</span> minor-&gt;dev;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_file</span> *<span class="title">priv</span>;</span></span><br><span class="line">        <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (filp-&gt;f_flags &amp; O_EXCL)</span><br><span class="line">                <span class="keyword">return</span> -EBUSY;  <span class="comment">/* No exclusive opens */</span></span><br><span class="line">        <span class="keyword">if</span> (!drm_cpu_valid())</span><br><span class="line">                <span class="keyword">return</span> -EINVAL;</span><br><span class="line">        <span class="keyword">if</span> (dev-&gt;switch_power_state != DRM_SWITCH_POWER_ON &amp;&amp;</span><br><span class="line">            dev-&gt;switch_power_state != DRM_SWITCH_POWER_DYNAMIC_OFF)</span><br><span class="line">                <span class="keyword">return</span> -EINVAL;</span><br><span class="line"></span><br><span class="line">        drm_dbg_core(dev, <span class="string">&quot;comm=\&quot;%s\&quot;, pid=%d, minor=%d\n&quot;</span>,</span><br><span class="line">                     current-&gt;comm, task_pid_nr(current), minor-&gt;index);</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 动态分配并初始化struct drm_file</span></span><br><span class="line">        priv = drm_file_alloc(minor);</span><br><span class="line">        <span class="keyword">if</span> (IS_ERR(priv))</span><br><span class="line">                <span class="keyword">return</span> PTR_ERR(priv);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (drm_is_primary_client(priv)) &#123;</span><br><span class="line">                ret = drm_master_open(priv);</span><br><span class="line">                <span class="keyword">if</span> (ret) &#123;</span><br><span class="line">                        drm_file_free(priv);</span><br><span class="line">                        <span class="keyword">return</span> ret;</span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 保存为file的私有数据</span></span><br><span class="line">        filp-&gt;private_data = priv;</span><br><span class="line">        filp-&gt;f_mode |= FMODE_UNSIGNED_OFFSET;</span><br><span class="line">        priv-&gt;filp = filp;</span><br><span class="line"></span><br><span class="line">        mutex_lock(&amp;dev-&gt;filelist_mutex);</span><br><span class="line">        list_add(&amp;priv-&gt;lhead, &amp;dev-&gt;filelist);</span><br><span class="line">        mutex_unlock(&amp;dev-&gt;filelist_mutex);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="4-2-内存映射"><a href="#4-2-内存映射" class="headerlink" title="4.2 内存映射"></a>4.2 内存映射</h4><p><code>nmap</code>用于将物理内存<code>dumb buffer</code>映射到用户空间，让应用程序可以直接访问物理内存。<br><code>drm_gem_mmap</code>函数定义在<code>drivers/gpu/drm/drm_gem.c</code>，内容如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * drm_gem_mmap - memory map routine for GEM objects</span></span><br><span class="line"><span class="comment"> * @filp: DRM file pointer</span></span><br><span class="line"><span class="comment"> * @vma: VMA for the area to be mapped</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * If a driver supports GEM object mapping, mmap calls on the DRM file</span></span><br><span class="line"><span class="comment"> * descriptor will end up here.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Look up the GEM object based on the offset passed in (vma-&gt;vm_pgoff will</span></span><br><span class="line"><span class="comment"> * contain the fake offset we created when the GTT map ioctl was called on</span></span><br><span class="line"><span class="comment"> * the object) and map it with a call to drm_gem_mmap_obj().</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * If the caller is not granted access to the buffer object, the mmap will fail</span></span><br><span class="line"><span class="comment"> * with EACCES. Please see the vma manager for more information.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">drm_gem_mmap</span><span class="params">(<span class="keyword">struct</span> file *filp, <span class="keyword">struct</span> vm_area_struct *vma)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_file</span> *<span class="title">priv</span> =</span> filp-&gt;private_data;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span> =</span> priv-&gt;minor-&gt;dev;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_gem_object</span> *<span class="title">obj</span> =</span> <span class="literal">NULL</span>;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_vma_offset_node</span> *<span class="title">node</span>;</span></span><br><span class="line">        <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 检查drm设备是否已被拔出</span></span><br><span class="line">        <span class="keyword">if</span> (drm_dev_is_unplugged(dev))</span><br><span class="line">                <span class="keyword">return</span> -ENODEV;</span><br><span class="line"></span><br><span class="line">		<span class="comment">// 锁定VMA管理器</span></span><br><span class="line">        drm_vma_offset_lock_lookup(dev-&gt;vma_offset_manager);</span><br><span class="line">        node = drm_vma_offset_exact_lookup_locked(dev-&gt;vma_offset_manager,</span><br><span class="line">                                                  vma-&gt;vm_pgoff,</span><br><span class="line">                                                  vma_pages(vma));</span><br><span class="line">        <span class="keyword">if</span> (likely(node)) &#123;</span><br><span class="line">                obj = container_of(node, <span class="keyword">struct</span> drm_gem_object, vma_node);</span><br><span class="line">                <span class="comment">/*</span></span><br><span class="line"><span class="comment">                 * When the object is being freed, after it hits 0-refcnt it</span></span><br><span class="line"><span class="comment">                 * proceeds to tear down the object. In the process it will</span></span><br><span class="line"><span class="comment">                 * attempt to remove the VMA offset and so acquire this</span></span><br><span class="line"><span class="comment">                 * mgr-&gt;vm_lock.  Therefore if we find an object with a 0-refcnt</span></span><br><span class="line"><span class="comment">                 * that matches our range, we know it is in the process of being</span></span><br><span class="line"><span class="comment">                 * destroyed and will be freed as soon as we release the lock -</span></span><br><span class="line"><span class="comment">                 * so we have to check for the 0-refcnted object and treat it as</span></span><br><span class="line"><span class="comment">                 * invalid.</span></span><br><span class="line"><span class="comment">                 */</span></span><br><span class="line">                <span class="keyword">if</span> (!kref_get_unless_zero(&amp;obj-&gt;refcount))</span><br><span class="line">                        obj = <span class="literal">NULL</span>;</span><br><span class="line">        &#125;</span><br><span class="line">		<span class="comment">// 解锁VMA管理器</span></span><br><span class="line">        drm_vma_offset_unlock_lookup(dev-&gt;vma_offset_manager);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!obj)</span><br><span class="line">                <span class="keyword">return</span> -EINVAL;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!drm_vma_node_is_allowed(node, priv)) &#123;</span><br><span class="line">                drm_gem_object_put(obj);</span><br><span class="line">                <span class="keyword">return</span> -EACCES;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">		<span class="comment">// Set up the VMA to prepare mapping of the GEM object using the GEM object&#x27;s vm_ops</span></span><br><span class="line">        ret = drm_gem_mmap_obj(obj, drm_vma_node_size(node) &lt;&lt; PAGE_SHIFT,</span><br><span class="line">                               vma);</span><br><span class="line"></span><br><span class="line">		<span class="comment">// GEM对象引用计数-1</span></span><br><span class="line">        drm_gem_object_put(obj);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="五、rockchip-drm-bind"><a href="#五、rockchip-drm-bind" class="headerlink" title="五、rockchip_drm_bind"></a>五、<code>rockchip_drm_bind</code></h3><p>我们定位到<code>drivers/gpu/drm/rockchip/rockchip_drm_drv.c</code>文件的函数<code>rockchip_drm_bind</code>，该函数用于绑定设备并初始化<code>DRM</code>驱动；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rockchip_drm_bind</span><span class="params">(<span class="keyword">struct</span> device *dev)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">drm_dev</span>;</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">rockchip_drm_private</span> *<span class="title">private</span>;</span></span><br><span class="line">        <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* 1. Remove existing drivers that may own the framebuffer memory. */</span></span><br><span class="line">        ret = drm_aperture_remove_framebuffers(<span class="literal">false</span>, &amp;rockchip_drm_driver);</span><br><span class="line">        <span class="keyword">if</span> (ret) &#123;</span><br><span class="line">                DRM_DEV_ERROR(dev,</span><br><span class="line">                              <span class="string">&quot;Failed to remove existing framebuffers - %d.\n&quot;</span>,</span><br><span class="line">                              ret);</span><br><span class="line">                <span class="keyword">return</span> ret;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">	    <span class="comment">// 2. 动态分配并初始化struct drm_device实例</span></span><br><span class="line">        drm_dev = drm_dev_alloc(&amp;rockchip_drm_driver, dev); </span><br><span class="line">        <span class="keyword">if</span> (IS_ERR(drm_dev))</span><br><span class="line">                <span class="keyword">return</span> PTR_ERR(drm_dev);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 3. 设置drm设备驱动私有数据为drm设备</span></span><br><span class="line">        dev_set_drvdata(dev, drm_dev); </span><br><span class="line"></span><br><span class="line">        <span class="comment">// 4. 动态分配rockchip_drm_private</span></span><br><span class="line">        private = devm_kzalloc(drm_dev-&gt;dev, <span class="keyword">sizeof</span>(*private), GFP_KERNEL); </span><br><span class="line">        <span class="keyword">if</span> (!private) &#123;</span><br><span class="line">                ret = -ENOMEM;</span><br><span class="line">                <span class="keyword">goto</span> err_free;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        drm_dev-&gt;dev_private = private;  </span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 5. 初始化drm_device中mode_config结构体</span></span><br><span class="line">        ret = drmm_mode_config_init(drm_dev); </span><br><span class="line">        <span class="keyword">if</span> (ret)</span><br><span class="line">                <span class="keyword">goto</span> err_free;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 初始化drm_device中mode_config的中成员</span></span><br><span class="line">        rockchip_drm_mode_config_init(drm_dev);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* 6. Try to bind all sub drivers. 执行按顺序执行显示子系统的各个组件的bind函数 */</span></span><br><span class="line">        ret = component_bind_all(dev, drm_dev);</span><br><span class="line">        <span class="keyword">if</span> (ret)</span><br><span class="line">                <span class="keyword">goto</span> err_free;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 7. 初始化IOMMU</span></span><br><span class="line">        ret = rockchip_drm_init_iommu(drm_dev);</span><br><span class="line">        <span class="keyword">if</span> (ret)</span><br><span class="line">                <span class="keyword">goto</span> err_unbind_all;</span><br><span class="line"></span><br><span class="line">	    <span class="comment">// 8.初始化vblank</span></span><br><span class="line">        ret = drm_vblank_init(drm_dev, drm_dev-&gt;mode_config.num_crtc);</span><br><span class="line">        <span class="keyword">if</span> (ret)</span><br><span class="line">                <span class="keyword">goto</span> err_iommu_cleanup;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 9. 重置模式配置</span></span><br><span class="line">        drm_mode_config_reset(drm_dev);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* 10.init kms poll for handling hpd */</span></span><br><span class="line">        drm_kms_helper_poll_init(drm_dev);</span><br><span class="line"></span><br><span class="line">	    <span class="comment">// 11.注册drm设备</span></span><br><span class="line">        ret = drm_dev_register(drm_dev, <span class="number">0</span>); </span><br><span class="line">        <span class="keyword">if</span> (ret)</span><br><span class="line">                <span class="keyword">goto</span> err_kms_helper_poll_fini;</span><br><span class="line"></span><br><span class="line">	    <span class="comment">// 12.设置帧缓冲设备</span></span><br><span class="line">        drm_fbdev_generic_setup(drm_dev, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">err_kms_helper_poll_fini:</span><br><span class="line">        drm_kms_helper_poll_fini(drm_dev);</span><br><span class="line">err_iommu_cleanup:</span><br><span class="line">        rockchip_iommu_cleanup(drm_dev);</span><br><span class="line">err_unbind_all:</span><br><span class="line">        component_unbind_all(dev, drm_dev);</span><br><span class="line">err_free:</span><br><span class="line">        drm_dev_put(drm_dev);</span><br><span class="line">        <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>函数主要步骤如下：</p>
<p>(1) 首先，通过调用<code>drm_aperture_remove_framebuffers</code>函数，移除可能拥有<code>framebuffer memory</code>的现有驱动程序；</p>
<p>为什么要执行这个操作呢？对于一个图形设备来说，可能有多个驱动程序提供支持，但在任何给定的事件只能有一个驱动程序处于活动状态。许多系统在引导过程的早期加载通用图形驱动程序，例如<code>EFI-GOP</code>或<code>VESA</code>，在后续的引导阶段，它们会将通用驱动程序替换为专用的、针对具体硬件的驱动程序。为了接管该设备，专用驱动程序首先必须移除通用驱动程序。<code>DRM aperture</code>函数负责管理<code>DRM framebuffer</code>内存的所有权和驱动程序之间的交接；</p>
<p>更多内容可以参考：<a target="_blank" rel="noopener" href="https://docs.kernel.org/gpu/drm-internals.html#managing-ownership-of-the-framebuffer-aperture"><code>Managing Ownership of the Framebuffer Aperture</code></a>。</p>
<p>(2) 接下来，使用<code>drm_dev_alloc</code>函数为设备动态分配一个<code>struct drm_device</code>结构体，并将其保存在<code>drm_dev</code>指针中；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">drm_dev = drm_dev_alloc(&amp;rockchip_drm_driver, dev); </span><br></pre></td></tr></table></figure>

<p>(3) 然后，使用<code>dev_set_drvdata</code>函数将设备的驱动私有数据设置为<code>drm_dev</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">dev_set_drvdata(dev, drm_dev); </span><br></pre></td></tr></table></figure>

<p>(4) 使用<code>devm_kzalloc</code>函数为<code>drm_dev</code>动态分配一个<code>rockchip_drm_private</code>结构体，并将其保存在<code>drm_dev-&gt;dev_private</code>指针中；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">private = devm_kzalloc(drm_dev-&gt;dev, <span class="keyword">sizeof</span>(*private), GFP_KERNEL)</span><br></pre></td></tr></table></figure>

<p>(5) 调用<code>drmm_mode_config_init</code>函数和<code>rockchip_drm_mode_config_init</code>函数对<code>drm_dev</code>进行模式配置的初始化；</p>
<p>(6) 调用<code>component_bind_all</code>函数，执行按顺序执行显示子系统的各个组件的<code>bind</code>函数；</p>
<p>(7) 调用<code>rockchip_drm_init_iommu</code>函数初始化<code>IOMMU</code>；</p>
<p>(8) 调用<code>drm_vblank_init</code>函数初始化<code>vblank</code>；</p>
<p>(9) 调用<code>drm_mode_config_reset</code>函数重置模式配置；</p>
<p>(10) 调用<code>drm_kms_helper_poll_init</code>函数初始化<code>KMS</code>轮询以处理<code>HPD（Hot Plug Detect）</code>；</p>
<p>(11) 在所有准备工作都完成后，调用<code>drm_dev_register</code>函数注册<code>DRM</code>设备；</p>
<p>(12) 调用<code>drm_fbdev_generic_setup</code>函数设置帧缓冲设备；</p>
<h4 id="5-1-初始化drm设备"><a href="#5-1-初始化drm设备" class="headerlink" title="5.1 初始化drm设备"></a>5.1 初始化<code>drm</code>设备</h4><p>一个<code>drm</code>驱动的设备由<code>struct drm_device</code>来表示，这里调用<code>drm_dev_alloc</code>进行分配和初始化一个<code>struct drm_device</code>实例，<code>drm_dev_alloc</code>函数定义在<code>drivers/gpu/drm/drm_drv.c</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * drm_dev_alloc - Allocate new DRM device</span></span><br><span class="line"><span class="comment"> * @driver: DRM driver to allocate device for</span></span><br><span class="line"><span class="comment"> * @parent: Parent device object</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This is the deprecated version of devm_drm_dev_alloc(), which does not support</span></span><br><span class="line"><span class="comment"> * subclassing through embedding the struct &amp;drm_device in a driver private</span></span><br><span class="line"><span class="comment"> * structure, and which does not support automatic cleanup through devres.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * RETURNS:</span></span><br><span class="line"><span class="comment"> * Pointer to new DRM device, or ERR_PTR on failure.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">struct</span> drm_device *<span class="title function_">drm_dev_alloc</span><span class="params">(<span class="type">const</span> <span class="keyword">struct</span> drm_driver *driver,</span></span><br><span class="line"><span class="params">                                 <span class="keyword">struct</span> device *parent)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_device</span> *<span class="title">dev</span>;</span></span><br><span class="line">        <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 动态分配一个struct drm_device </span></span><br><span class="line">        dev = kzalloc(<span class="keyword">sizeof</span>(*dev), GFP_KERNEL);</span><br><span class="line">        <span class="keyword">if</span> (!dev)</span><br><span class="line">                <span class="keyword">return</span> ERR_PTR(-ENOMEM);</span><br><span class="line"></span><br><span class="line">        ret = drm_dev_init(dev, driver, parent);</span><br><span class="line">        <span class="keyword">if</span> (ret) &#123;</span><br><span class="line">                kfree(dev);</span><br><span class="line">                <span class="keyword">return</span> ERR_PTR(ret);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        drmm_add_final_kfree(dev, dev);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> dev;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><code>drm_dev_alloc</code>函数时一个已废弃版本，它不支持在驱动程序的私有结构中嵌入<code>struct drm_device</code>来实现子类化，并且不支持通过<code>devres</code>进行自动清理。</p>
<p><code>drm_dev_alloc</code>函数内部调用<code>drm_dev_init</code>去初始化<code>struct drm_device</code>实例。</p>
<h4 id="5-2-模式配置初始化"><a href="#5-2-模式配置初始化" class="headerlink" title="5.2 模式配置初始化"></a>5.2 模式配置初始化</h4><p>下面我们分析一下<code>drmm_mode_config_init</code>函数和<code>rockchip_drm_mode_config_init</code>函数；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 调用drm_mode_config_init初始化drm_device中mode_config结构体</span></span><br><span class="line">ret = drmm_mode_config_init(drm_dev);</span><br><span class="line"><span class="keyword">if</span> (ret)</span><br><span class="line">    <span class="keyword">goto</span> err_free;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 填充mode_config中min_width, min_height、max_width, max_height的值，这些值是framebuffer的大小限制</span></span><br><span class="line"><span class="comment">// 设置mode_config-&gt;funcs指针，本质是一组由驱动实现的回调函数</span></span><br><span class="line">rockchip_drm_mode_config_init(drm_dev);</span><br></pre></td></tr></table></figure>

<p><code>rockchip_drm_mode_config_init</code>函数定义在<code>drivers/gpu/drm/rockchip/rockchip_drm_fb.c</code>，内容如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">rockchip_drm_mode_config_init</span><span class="params">(<span class="keyword">struct</span> drm_device *dev)</span></span><br><span class="line">&#123;</span><br><span class="line">        dev-&gt;mode_config.min_width = <span class="number">0</span>;</span><br><span class="line">        dev-&gt;mode_config.min_height = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/*</span></span><br><span class="line"><span class="comment">         * set max width and height as default value(4096x4096).</span></span><br><span class="line"><span class="comment">         * this value would be used to check framebuffer size limitation</span></span><br><span class="line"><span class="comment">         * at drm_mode_addfb().</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        dev-&gt;mode_config.max_width = <span class="number">4096</span>;</span><br><span class="line">        dev-&gt;mode_config.max_height = <span class="number">4096</span>;</span><br><span class="line"></span><br><span class="line">        dev-&gt;mode_config.funcs = &amp;rockchip_drm_mode_config_funcs;</span><br><span class="line">        dev-&gt;mode_config.helper_private = &amp;rockchip_mode_config_helpers;</span><br><span class="line"></span><br><span class="line">        dev-&gt;mode_config.normalize_zpos = <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="5-2-1-func"><a href="#5-2-1-func" class="headerlink" title="5.2.1 func"></a>5.2.1 <code>func</code></h5><p> <code>drm</code>显示器模式设置<code>mode_config</code>回调函数<code>funcs</code>被设置为<code>rockchip_drm_mode_config_funcs</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">drm_mode_config_funcs</span> <span class="title">rockchip_drm_mode_config_funcs</span> =</span> &#123;</span><br><span class="line">        .fb_create = rockchip_fb_create,</span><br><span class="line">        .<span class="type">atomic_check</span> = drm_atomic_helper_check,</span><br><span class="line">        .<span class="type">atomic_commit</span> = drm_atomic_helper_commit,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p><code>fb_create</code> 回调接口用于创建<code>framebuffer object</code>，并绑定<code>GEM</code>对象。<code>rockchip_fb_create</code>定义如下；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">drm_framebuffer_funcs</span> <span class="title">rockchip_drm_fb_funcs</span> =</span> &#123;</span><br><span class="line">        .destroy       = drm_gem_fb_destroy,</span><br><span class="line">        .create_handle = drm_gem_fb_create_handle,</span><br><span class="line">        .dirty         = drm_atomic_helper_dirtyfb,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="keyword">struct</span> drm_framebuffer *</span><br><span class="line"><span class="title function_">rockchip_fb_create</span><span class="params">(<span class="keyword">struct</span> drm_device *dev, <span class="keyword">struct</span> drm_file *file,</span></span><br><span class="line"><span class="params">                   <span class="type">const</span> <span class="keyword">struct</span> drm_mode_fb_cmd2 *mode_cmd)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">drm_afbc_framebuffer</span> *<span class="title">afbc_fb</span>;</span></span><br><span class="line">        <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">drm_format_info</span> *<span class="title">info</span>;</span></span><br><span class="line">        <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 获取drm格式</span></span><br><span class="line">        info = drm_get_format_info(dev, mode_cmd);</span><br><span class="line">        <span class="keyword">if</span> (!info)</span><br><span class="line">                <span class="keyword">return</span> ERR_PTR(-ENOMEM);</span><br><span class="line"></span><br><span class="line">        afbc_fb = kzalloc(<span class="keyword">sizeof</span>(*afbc_fb), GFP_KERNEL);</span><br><span class="line">        <span class="keyword">if</span> (!afbc_fb)</span><br><span class="line">                <span class="keyword">return</span> ERR_PTR(-ENOMEM);</span><br><span class="line"></span><br><span class="line">        ret = drm_gem_fb_init_with_funcs(dev, &amp;afbc_fb-&gt;base, file, mode_cmd,</span><br><span class="line">                                         &amp;rockchip_drm_fb_funcs);</span><br><span class="line">        <span class="keyword">if</span> (ret) &#123;</span><br><span class="line">                kfree(afbc_fb);</span><br><span class="line">                <span class="keyword">return</span> ERR_PTR(ret);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (drm_is_afbc(mode_cmd-&gt;modifier[<span class="number">0</span>])) &#123;</span><br><span class="line">                <span class="type">int</span> ret, i;</span><br><span class="line"></span><br><span class="line">                ret = drm_gem_fb_afbc_init(dev, mode_cmd, afbc_fb);</span><br><span class="line">                <span class="keyword">if</span> (ret) &#123;</span><br><span class="line">                        <span class="class"><span class="keyword">struct</span> <span class="title">drm_gem_object</span> **<span class="title">obj</span> =</span> afbc_fb-&gt;base.obj;</span><br><span class="line"></span><br><span class="line">                        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; info-&gt;num_planes; ++i)</span><br><span class="line">                                drm_gem_object_put(obj[i]);</span><br><span class="line"></span><br><span class="line">                        kfree(afbc_fb);</span><br><span class="line">                        <span class="keyword">return</span> ERR_PTR(ret);</span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> &amp;afbc_fb-&gt;base;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="5-2-2-helper-private"><a href="#5-2-2-helper-private" class="headerlink" title="5.2.2 helper_private"></a>5.2.2 <code>helper_private</code></h5><p> <code>drm</code>显示器模式设置<code>mode_config</code>中间层私有数据<code>helper_private</code>被设置为了<code>rockchip_mode_config_helpers</code>；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">drm_mode_config_helper_funcs</span> <span class="title">rockchip_mode_config_helpers</span> =</span> &#123;</span><br><span class="line">        .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h4 id="5-3-component-bind-all"><a href="#5-3-component-bind-all" class="headerlink" title="5.3 component_bind_all"></a>5.3 <code>component_bind_all</code></h4><p>在<code>component_bind_all</code>函数我们已经在<a target="_blank" rel="noopener" href="https://www.cnblogs.com/zyly/p/17678424.html#_label2_4"><code>《Rockchip RK3399 - component</code>框架》</a>详细介绍了；</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * component_bind_all - bind all components of an aggregate driver</span></span><br><span class="line"><span class="comment"> * @parent: parent device of the aggregate driver</span></span><br><span class="line"><span class="comment"> * @data: opaque pointer, passed to all components</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Binds all components of the aggregate @dev by passing @data to their</span></span><br><span class="line"><span class="comment"> * &amp;component_ops.bind functions. Should be called from</span></span><br><span class="line"><span class="comment"> * &amp;component_master_ops.bind.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">component_bind_all</span><span class="params">(<span class="keyword">struct</span> device *parent, <span class="type">void</span> *data)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">aggregate_device</span> *<span class="title">adev</span>;</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">component</span> *<span class="title">c</span>;</span></span><br><span class="line">        <span class="type">size_t</span> i;</span><br><span class="line">        <span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        WARN_ON(!mutex_is_locked(&amp;component_mutex));</span><br><span class="line"></span><br><span class="line">    	<span class="comment">// 根据parent查找到aggregate_device</span></span><br><span class="line">        adev = __aggregate_find(parent, <span class="literal">NULL</span>);</span><br><span class="line">        <span class="keyword">if</span> (!adev)</span><br><span class="line">                <span class="keyword">return</span> -EINVAL;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Bind components in match order */</span></span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; adev-&gt;match-&gt;num; i++)</span><br><span class="line">            	<span class="comment">// duplicate为false时进入</span></span><br><span class="line">                <span class="keyword">if</span> (!adev-&gt;match-&gt;compare[i].duplicate) &#123;</span><br><span class="line">                        c = adev-&gt;match-&gt;compare[i].component;</span><br><span class="line">						<span class="comment">// 执行component的bind函数</span></span><br><span class="line">                        ret = component_bind(c, adev, data);</span><br><span class="line">                        <span class="keyword">if</span> (ret)</span><br><span class="line">                                <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (ret != <span class="number">0</span>) &#123; <span class="comment">// 正常不会走这里</span></span><br><span class="line">                <span class="keyword">for</span> (; i &gt; <span class="number">0</span>; i--)</span><br><span class="line">                        <span class="keyword">if</span> (!adev-&gt;match-&gt;compare[i - <span class="number">1</span>].duplicate) &#123;</span><br><span class="line">                                c = adev-&gt;match-&gt;compare[i - <span class="number">1</span>].component;</span><br><span class="line">                                component_unbind(c, adev, data);</span><br><span class="line">                        &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>首先通过设备<code>parent</code>找到与之关联的的<code>aggregate_device</code>，再按照<code>aggregate_device</code>→<code>component_match_array</code>→<code>component</code>的顺序找到<code>component</code>，然后就能调用<code>component</code>的<code>bind</code>函数。</p>
<h4 id="5-4-注册drm设备"><a href="#5-4-注册drm设备" class="headerlink" title="5.4 注册drm设备"></a>5.4 注册<code>drm</code>设备</h4><p>最后调用<code>drm_dev_register</code>注册<code>drm</code>设备。</p>
<p><strong>参考文章</strong></p>
<p><strong>[1] <a target="_blank" rel="noopener" href="https://blog.csdn.net/hexiaolong2009/category_9281458.html"><code>DRM (Direct Rendering Manager)</code></a></strong></p>
<p><strong>[2] <a target="_blank" rel="noopener" href="https://docs.kernel.org/gpu/drm-internals.html#display-driver-example"><code>linux Display driver example</code></a></strong></p>
<p><strong>[3] <a target="_blank" rel="noopener" href="https://www.jianshu.com/p/55c12c4e01cb"><code>Linux DRM</code>那些事-<code>component bind</code>解析</a></strong></p>
<p><strong>[4] <a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/534267979?utm_id=0&wd=&eqid=c86633fc0001a4990000000664883112"><code>DRM Display Driver Guide</code></a></strong></p>

        
      </div>

         
    </div>
    
     
  </div>
  
    
<nav id="article-nav">
  <a class="article-nav-btn left  disabled "
     >
    <i class="fa-solid fa-angle-left"></i>
    <p class="title-text">
        
    </p>
  </a>
  <a class="article-nav-btn right "
    
      href="/blog/2023/09/11/rk3399/Rockchip%20RK3399%20-%20DRM%E5%AD%90%E7%B3%BB%E7%BB%9F/"
      title=""
     >

    <p class="title-text">
      
        (No Title)
        
    </p>
    <i class="fa-solid fa-angle-right"></i>
  </a>
</nav>


  
</article>

 
    </div>
    <div id="footer-wrapper">
      <footer id="footer">
  
  <div id="footer-info" class="inner">
    
    &copy; 2023 Your Name<br>
    Powered by <a href="https://hexo.io/" target="_blank">Hexo</a> & Theme <a target="_blank" rel="noopener" href="https://github.com/saicaca/hexo-theme-vivia">Vivia</a>
  </div>
</footer>

    </div>
    <div class="back-to-top-wrapper">
    <button id="back-to-top-btn" class="back-to-top-btn hide" onclick="topFunction()">
        <i class="fa-solid fa-angle-up"></i>
    </button>
</div>

<script>
    function topFunction() {
        window.scroll({ top: 0, behavior: 'smooth' });
    }
    let btn = document.getElementById('back-to-top-btn');
    function scrollFunction() {
        if (document.body.scrollTop > 600 || document.documentElement.scrollTop > 600) {
            btn.classList.remove('hide')
        } else {
            btn.classList.add('hide')
        }
    }
    window.onscroll = function() {
        scrollFunction();
    }
</script>

  </div>
  <script src="/blog/js/light-dark-switch.js"></script>
</body>
</html>
